package com.example.ddd.infrastructure.lock;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 分布式锁管理器 - 基础设施层组件
 * 封装Redisson提供的分布式锁API，提供简单易用的接口
 */
@Component
public class DistributedLockManager {

    private final RedissonClient redissonClient;

    @Autowired
    public DistributedLockManager(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    /**
     * 获取锁
     * @param lockKey 锁的键
     * @param waitTime 等待时间
     * @param leaseTime 锁持有时间
     * @param timeUnit 时间单位
     * @return 是否获取到锁
     */
    public boolean lock(String lockKey, long waitTime, long leaseTime, TimeUnit timeUnit) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, timeUnit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }

    /**
     * 获取锁（无等待时间）
     * @param lockKey 锁的键
     * @param leaseTime 锁持有时间
     * @param timeUnit 时间单位
     * @return 是否获取到锁
     */
    public boolean lock(String lockKey, long leaseTime, TimeUnit timeUnit) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(0, leaseTime, timeUnit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }

    /**
     * 释放锁
     * @param lockKey 锁的键
     */
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    /**
     * 执行加锁的操作
     * @param lockKey 锁的键
     * @param waitTime 等待时间
     * @param leaseTime 锁持有时间
     * @param timeUnit 时间单位
     * @param callback 加锁后执行的回调函数
     * @param <T> 回调函数返回值类型
     * @return 回调函数的返回值，如果未获取到锁则返回null
     */
    public <T> T executeWithLock(String lockKey, long waitTime, long leaseTime, TimeUnit timeUnit, LockCallback<T> callback) {
        if (lock(lockKey, waitTime, leaseTime, timeUnit)) {
            try {
                return callback.execute();
            } finally {
                unlock(lockKey);
            }
        }
        return null;
    }

    /**
     * 锁回调接口
     * @param <T> 回调返回值类型
     */
    @FunctionalInterface
    public interface LockCallback<T> {
        T execute();
    }
}